package org.yeyu.service;

import org.apache.poi.ss.usermodel.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.yeyu.model.SearchResult;
import org.yeyu.utils.ExcelUtils;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Excel文件搜索服务
 */
public class SearchService {
    private static final Logger logger = LogManager.getLogger(SearchService.class);

    // 缓存表头检测结果，避免重复计算
    private final Map<String, Map<String, List<String>>> headerCache = new ConcurrentHashMap<>();

    // 最大缓存条目数
    private static final int MAX_CACHE_SIZE = 50;

    /**
     * 在Excel文件中搜索关键词
     * @param excelFile Excel文件
     * @param keyword 搜索关键词
     * @param customHeaderRows 自定义表头行
     * @param caseSensitive 是否区分大小写
     * @param wholeWord 是否全词匹配
     * @param useRegex 是否使用正则表达式
     * @param selectedSheets 选定的工作表列表，null表示搜索所有工作表
     * @return 搜索结果列表
     * @throws IOException 如果读取文件时发生错误
     */
    public List<SearchResult> searchInExcel(File excelFile, String keyword, Map<String, Integer> customHeaderRows,
            boolean caseSensitive, boolean wholeWord, boolean useRegex, List<String> selectedSheets) throws IOException {
        logger.info("开始在Excel文件中搜索: {}", keyword);
        List<SearchResult> results = new ArrayList<>();

        // 清理过期的缓存
        cleanUpCache();

        try (Workbook workbook = WorkbookFactory.create(excelFile)) {
            // 根据选择的工作表范围进行搜索
            List<String> sheetsToSearch = getSheetsToSearch(workbook, selectedSheets);

            for (String sheetName : sheetsToSearch) {
                Sheet sheet = workbook.getSheet(sheetName);
                if (sheet == null) {
                    logger.warn("工作表不存在: {}", sheetName);
                    continue; // 跳过不存在的工作表
                }

                // 检测表头
                List<String> headers = detectHeaders(sheet, sheetName, customHeaderRows);

                // 遍历每一行
                for (Row row : sheet) {
                    List<String> rowData = ExcelUtils.getRowData(row);
                    List<Integer> matchedColumns = new ArrayList<>();

                    // 检查是否匹配关键词
                    List<Integer> matches = checkKeywordMatch(rowData, keyword, caseSensitive, wholeWord, useRegex);
                    if (!matches.isEmpty()) {
                        results.add(new SearchResult(sheetName, row.getRowNum() + 1, rowData, matches, headers));
                    }
                }
            }
        }

        logger.info("搜索完成，找到 {} 条匹配记录", results.size());
        return results;
    }

    /**
     * 获取需要搜索的工作表列表
     * @param workbook Excel工作簿
     * @param selectedSheets 用户选择的工作表列表
     * @return 需要搜索的工作表列表
     */
    private List<String> getSheetsToSearch(Workbook workbook, List<String> selectedSheets) {
        List<String> sheetsToSearch = new ArrayList<>();

        if (selectedSheets == null || selectedSheets.isEmpty()) {
            // 如果没有选择特定工作表，则搜索所有工作表
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                sheetsToSearch.add(workbook.getSheetName(i));
            }
        } else {
            // 只搜索选定的工作表
            sheetsToSearch = new ArrayList<>(selectedSheets);
        }

        return sheetsToSearch;
    }

    /**
     * 检查行数据是否匹配关键词
     * @param rowData 行数据
     * @param keyword 搜索关键词
     * @param caseSensitive 是否区分大小写
     * @param wholeWord 是否全词匹配
     * @param useRegex 是否使用正则表达式
     * @return 匹配的列索引列表
     */
    private List<Integer> checkKeywordMatch(List<String> rowData, String keyword, 
            boolean caseSensitive, boolean wholeWord, boolean useRegex) {
        List<Integer> matchedColumns = new ArrayList<>();
        String keywordToCheck = caseSensitive ? keyword : keyword.toLowerCase();

        for (int i = 0; i < rowData.size(); i++) {
            String cellValue = rowData.get(i);
            if (cellValue == null || cellValue.isEmpty()) {
                continue;
            }

            String cellValueToCheck = caseSensitive ? cellValue : cellValue.toLowerCase();
            boolean match = false;

            try {
                if (useRegex) {
                    // 使用正则表达式匹配
                    match = cellValueToCheck.matches(keywordToCheck);
                } else if (wholeWord) {
                    // 全词匹配
                    match = cellValueToCheck.equals(keywordToCheck) ||
                            cellValueToCheck.matches(".*\\b" + java.util.regex.Pattern.quote(keywordToCheck) + "\\b.*");
                } else {
                    // 部分匹配
                    match = cellValueToCheck.contains(keywordToCheck);
                }
            } catch (Exception e) {
                logger.warn("关键词匹配出错: {}", e.getMessage());
                // 正则表达式无效，回退到普通匹配
                match = cellValueToCheck.contains(keywordToCheck);
            }

            if (match) {
                matchedColumns.add(i);
            }
        }

        return matchedColumns;
    }

    /**
     * 检测表头
     * @param sheet Excel工作表
     * @param sheetName 工作表名称
     * @param customHeaderRows 自定义表头行
     * @return 表头列表
     */
    private List<String> detectHeaders(Sheet sheet, String sheetName, Map<String, Integer> customHeaderRows) {
        // 创建缓存键
        String cacheKey = sheetName;

        // 检查缓存
        if (headerCache.containsKey(cacheKey) && headerCache.get(cacheKey).containsKey(sheetName)) {
            return headerCache.get(cacheKey).get(sheetName);
        }

        List<String> headers = new ArrayList<>();

        // 查找用户自定义的表头行
        if (customHeaderRows != null && customHeaderRows.containsKey(sheetName)) {
            int customHeaderRow = customHeaderRows.get(sheetName);
            if (customHeaderRow > 0) {
                Row headerRowObj = sheet.getRow(customHeaderRow - 1); // 转换为0-based索引
                if (headerRowObj != null) {
                    for (int colIndex = 0; colIndex < headerRowObj.getLastCellNum(); colIndex++) {
                        Cell cell = headerRowObj.getCell(colIndex);
                        headers.add(ExcelUtils.getCellValueAsString(cell));
                    }
                    // 添加到缓存
                    addToCache(cacheKey, sheetName, headers);
                    return headers;
                }
            }
        }

        // 如果没有指定，使用默认逻辑检测表头
        int maxHeaderRows = 5; // 最多检查前5行
        int headerRow = -1;

        for (int rowIdx = 0; rowIdx < Math.min(maxHeaderRows, sheet.getLastRowNum() + 1); rowIdx++) {
            Row row = sheet.getRow(rowIdx);
            if (row == null) continue;

            // 检查是否为表头行（包含文本且不是纯数字）
            boolean hasTextContent = false;
            boolean hasNumericContent = false;

            for (Cell cell : row) {
                String cellValue = ExcelUtils.getCellValueAsString(cell);
                if (!cellValue.isEmpty()) {
                    if (isPureNumber(cellValue)) {
                        hasNumericContent = true;
                    } else {
                        hasTextContent = true;
                    }
                }
            }

            // 如果这一行有文本内容但没有纯数字，可能是表头
            if (hasTextContent && !hasNumericContent) {
                headerRow = rowIdx;
                break;
            }
        }

        // 如果找到表头行，提取表头
        if (headerRow != -1) {
            Row headerRowObj = sheet.getRow(headerRow);
            if (headerRowObj != null) {
                for (int colIndex = 0; colIndex < headerRowObj.getLastCellNum(); colIndex++) {
                    Cell cell = headerRowObj.getCell(colIndex);
                    headers.add(ExcelUtils.getCellValueAsString(cell));
                }
            }
        } else {
            // 如果没有找到合适的表头行，创建默认列名
            int maxColumns = 0;
            for (Row row : sheet) {
                if (row.getLastCellNum() > maxColumns) {
                    maxColumns = row.getLastCellNum();
                }
            }
            for (int i = 0; i < maxColumns; i++) {
                headers.add("列" + (i + 1));
            }
        }

        // 添加到缓存
        addToCache(cacheKey, sheetName, headers);

        return headers;
    }

    /**
     * 检查字符串是否为纯数字
     * @param value 要检查的字符串
     * @return 如果是纯数字返回true，否则返回false
     */
    private boolean isPureNumber(String value) {
        if (value == null || value.isEmpty()) {
            return false;
        }
        try {
            Double.parseDouble(value);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 添加表头到缓存
     * @param cacheKey 缓存键
     * @param sheetName 工作表名称
     * @param headers 表头列表
     */
    private void addToCache(String cacheKey, String sheetName, List<String> headers) {
        // 如果缓存已满，清理最旧的条目
        if (headerCache.size() >= MAX_CACHE_SIZE) {
            headerCache.remove(headerCache.keySet().iterator().next());
        }

        if (!headerCache.containsKey(cacheKey)) {
            headerCache.put(cacheKey, new HashMap<>());
        }

        headerCache.get(cacheKey).put(sheetName, new ArrayList<>(headers));
    }

    /**
     * 清理过期的缓存
     */
    private void cleanUpCache() {
        // 如果缓存大小超过最大值，清理最旧的25%条目
        if (headerCache.size() > MAX_CACHE_SIZE) {
            int itemsToRemove = (int) (headerCache.size() * 0.25);
            List<String> keysToRemove = new ArrayList<>(headerCache.keySet());
            for (int i = 0; i < itemsToRemove && i < keysToRemove.size(); i++) {
                headerCache.remove(keysToRemove.get(i));
            }
        }
    }
}
